package.cpath  = "./?.so;" .. package.cpath
local skynet = require "skynet"
local cluster = require "skynet.cluster"
local netpack = require "skynet.websocketnetpack"
local base = require "base"
local filelog = require "filelog"
local filename = "robotnode.lua"
local configdao = require "configdao"
local md5 = require "md5"

require "skynet.manager"
require "pubenum"

local platform2login_key = ""

local Robotnode = {
	protobuf = nil, 
	decode = nil,
	socket = nil,
	eventpool = {},
}

function Robotnode:process(session, source, calltype, msgname, ...)
	if msgname == nil then
		filelog.sys_error(filename.." line22 robotnode:process invalid msgname")
		return
	end
    
    if self[msgname] then
        local func = self[msgname]
        return func(self, ...)
    end

	local f = self.eventpool[msgname]
	if f == nil then
		filelog.sys_error(filename.." line28 robotnode:processinvalid msgname:"..msgname, ...)		
		return
	end
	local status, result = skynet.pcall(f.process, session, source, ...)
	if not status then
		filelog.sys_error(filename.." line33 robotnode:process skynet.pcall failed", msgname, result, ...)
	end
end

----------------------------------

--向服务器发送请求
function Robotnode:send_reqmsg_toserver(fd, msgname, msgbody)
	self.socket.send(fd, self.decode.c2spack(self.protobuf, msgname, msgbody))
end

--处理响应包
function Robotnode:handle_response(curfd, msghead, msgbody)
    local name = msghead.msgname
    local retcode = msghead.retcode or 0
    if retcode ~= 0 then
        if name == "authR" or name == "entergameR" then
            return false
        end
    end

    if msgbody then
        if name == "authR" then
            local msg = {
                gateip = msgbody.gateip,
                rid = msgbody.rid,
                gateport = msgbody.gateport,    
                expiretime = msgbody.expiretime,
                gatetoken = msgbody.gatetoken,
                username = msgbody.username,
                cpass = msgbody.cpass,
            }
            return msg
        elseif name == "entergameR" then
            local result = {
                rid = msgbody.baseinfo.rid,
                coin = msgbody.baseinfo.coin,
                diamond = msgbody.baseinfo.diamond,
                lock_coin = msgbody.baseinfo.lock_coin,
                lock_diamond = msgbody.baseinfo.lock_diamond,
            }
            return result
        end
    end
end

--接收包
function Robotnode:recv_package(fd)
	local r, istimeout = self.socket.recv(fd, 10)
	if not r then
		return
	end
	if r == "" and not istimeout then
		return false
	end
	return r
end

--处理服务器发来的数据包
function Robotnode:dispatch_package(fd)
    if not fd then
        return
    end

	while true do
		local data = self:recv_package(fd)
		if data == false then
			break
		elseif data and data ~= "" then
            local msghead,msgbody = self.decode.s2cunpack(self.protobuf, data)
            return self:handle_response(fd, msghead, msgbody)
        end
        skynet.sleep(2)
	end
end

--生成用户信息(用户名，密码)
function Robotnode:gen_userinfo()
    local head = "_robot_"
    local id = skynet.call(".nodeuuid", "lua", "getuuid")
    local randnum = base.get_random(100000,999999)
    local username = head .. tostring(id) .. tostring(randnum)
    local cpass = md5.sumhexa(base.get_random(100000,999999))
    return username,cpass
end

--登录
function Robotnode:login(ip, port)
    local fd = self.socket.connect(ip, port)
    if not fd then
        return false
    end

    local username,cpass = self:gen_userinfo()
    local tokentime = os.time()
    local newtoken = md5.sumhexa(username .. tokentime .. platform2login_key ) .. tokentime
    self:send_reqmsg_toserver(fd,"authother",{username = username, cpass = cpass, logintoken = newtoken})
    local result = self:dispatch_package(fd)
    self.socket.close(fd)

    return result
end

--进入游戏
function Robotnode:entergame(ip, port, conf)
    local fd = self.socket.connect(ip, port)
    if not fd then
        return false
    end

    self:send_reqmsg_toserver(fd, "entergame", {
        rid = conf.rid, uid = conf.uid, gatetoken = conf.gatetoken,
        expiretime = conf.expiretime, agencyrid = conf.agencyrid,
        clientver = "0000",
    })
    local result = self:dispatch_package(fd)
    self.socket.close(fd)

     return result
end

--导入机器人数据
function Robotnode:load_robotinfo(filename)
    filename = filename or "robot_info.dat"

    local robot_info = {}
    local iter = io.lines(filename)
    for str in iter do
        local id,rolename,logo,sex = string.match(str,"\"(.+)\",\"(.+)\",\"(.+)\",\"(.+)\"")
        table.insert(robot_info,{id = id, rolename = rolename, logo = logo, sex = sex})
    end

    --随机顺序
    local j = 0
    local first = 1
    local last = #robot_info
    for i = first + 1,last do
        j = first + math.random(0, i - first)
        robot_info[i],robot_info[j] = robot_info[j],robot_info[i]
    end

    return robot_info
end

--创建机器人信息
function Robotnode:gen_robotinfo(robot_infos)
    local infos = table.remove(robot_infos)
    if not infos then
        return {level = 99, sex = math.random(1,2)}
    end

    local robotinfo = {
        level = 99,
        rolename = infos.rolename,
        logo = infos.logo,
        sex = tonumber(infos.sex),
    }
    if robotinfo.sex == 0 then
        robotinfo.sex = 2
    end

    return robotinfo
end

--批量生成机器人
function Robotnode:batch_build_robots(num, conf)
    conf = conf or {}
 
    local count = 0
    local failed_num = 0
    local robot_list = {}
    local failed_list = {}
    local ip = self.loginsvr_conf.ip
    local port = self.loginsvr_conf.port

    --导入机器人数据
    local robot_infos = self:load_robotinfo(conf.filename)
    if not robot_infos then
        filelog.sys_error("Robotnode.batch_build_robots: load robot info failed!")
        return false
    end

    if not num then
        num = #robot_infos
    elseif num > #robot_infos then
        num = #robot_infos
    end
    filelog.sys_info("Robotnode.batch_build_robots: start build robots, please waiting...", num)

    while count < num do
        local baseinfo = nil
        local result = self:login(ip, port)
        if result then
            baseinfo = self:entergame(ip, result.gateport, result)
        end
        if baseinfo then
            local item = {
                rid = baseinfo.rid,
                username = result.username,
                cpass = result.cpass,
                money = {
                    coin = baseinfo.coin,
                    diamond = baseinfo.diamond,
                    lock_coin = baseinfo.lock_coin,
                    lock_diamond = baseinfo.lock_diamond,
                }
            }
            table.insert(robot_list,item)
            count = count + 1
        else
            failed_num = failed_num + 1
            if failed_num >= num then
                filelog.sys_error("Robotnode.batch_build_robots: build robotr failed!", failed_num)
                return false
            end
            if result then
                table.insert(failed_list, result.rid)
            end
        end
    end

    --更新机器人数据
    for k,obj in pairs(robot_list) do
        local robotinfo = self:gen_robotinfo(robot_infos)
        local status,isok = skynet.pcall(cluster.call, "gatenode", ".router", "updateroleinfo", obj.rid, robotinfo, {})
        if not status or not isok then
            table.insert(failed_list, obj.rid)
            robot_list[k] = nil
            count = count - 1
        else
            skynet.pcall(cluster.call, "datanode", ".router", "select_rk", obj.rid, "rs_robot")
            skynet.pcall(cluster.call, "datanode", ".router", "update_rk", obj.rid, "rs_robot", 0, {username = obj.username, cpass = obj.cpass})
            --身上钱放回库存
            for moneytype,value in pairs(obj.money) do
                if value > 0 then
                    skynet.pcall(skynet.call, ".inventorymgr", "lua", "save_money", obj.rid, moneytype, value, value, nil)
                end
            end
        end
    end

    --删掉无效的机器人
    self:batch_destory_robots(failed_list)
    filelog.sys_info("Robotnode.batch_build_robots: build robots ok! count: " .. (count or 0))
    
    return count
end

--批量删除机器人
function Robotnode:batch_destory_robots(rids, timestamp)
    --暂不支持删除
end

---------------------------

function Robotnode:start()
	-- 重置protobuf解析器到全局唯一的解析器地址
	debug.getregistry().PROTOBUF_ENV = skynet.call(".pbcservice", "lua", "get_protobuf_env")
	self.protobuf = require "protobuf"
	self.decode = require "protopack"
    self.socket = require "client.websocket"
	
	skynet.dispatch("lua", function (session, source, ...)
        Robotnode:process(session, source,"lua", ...)
    end)
	self:init()
end

function Robotnode:add_eventbyname(name, event)
	self.eventpool[name] = require(event)
	self.eventpool[name].service = Robotnode
end

function  Robotnode:init()
	local loginconf = configdao.get_cfgsvrs_key("loginnode")
    local gateconf = configdao.get_cfgsvrs_key("gatenode")
    self.gatesvr_conf = { ip = "127.0.0.1", port = gateconf.svr_port }
    self.loginsvr_conf = { ip = "127.0.0.1", port = loginconf.svr_port }
    platform2login_key = configdao.get_cfgsvrs_key("platform2login_key")

    --初始化随机数种子
    math.randomseed(os.time())
    math.random()
end

skynet.start(function()
	Robotnode:start()
end)
